package com.ruige.account.weblog;

import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

/**
 * @author swallow
 * @create 2020/2/17
 * @description
 */
@Aspect
@Component
@Order(1)
@ConditionalOnBean(value = {HttpServletRequestWrapperFilter.class})
public class WebApiLogHandler {
    private static final Logger logger = LoggerFactory.getLogger(WebApiLogHandler.class);
    private ThreadLocal<Long> startTime = new ThreadLocal<>();
    private ThreadLocal<String> logStrLocal = new ThreadLocal<>();
    private static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");


    @Pointcut("execution(public * com.ruige..*.controller.*.*(..))")
    public void webLog() {
    }

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        LocalDateTime now = LocalDateTime.now();
        startTime.set(now.toEpochSecond(ZoneOffset.ofHours(8)));

        String httpMethod = request.getMethod();
        String contentType = request.getContentType();
        StringBuilder logSb = new StringBuilder();
        logSb.append("\n>>>>>>>>>>>>>");
        logSb.append("\n开始计时: ").append(dateTimeFormatter.format(now));
        logSb.append("\nHttp-接口请求");
        logSb.append("\nUri: ").append(request.getRequestURL().toString());
        logSb.append("\nHttp-Method: ").append(httpMethod);
        logSb.append("\nContent-Type: ").append(contentType);
        logSb.append("\nRequest-IP: ").append(request.getRemoteAddr());
        logSb.append("\nClass-Method: ").append(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logSb.append("\nParameter: ").append(JSONObject.toJSON(request.getParameterMap()));
        if (null != contentType && httpMethod != null && !httpMethod.equalsIgnoreCase("get")){
            if (contentType.equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE)
                    || contentType.equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)
                    || contentType.equalsIgnoreCase(MediaType.TEXT_XML_VALUE)
                    || contentType.equalsIgnoreCase(MediaType.TEXT_PLAIN_VALUE)
                    || contentType.equalsIgnoreCase(MediaType.APPLICATION_XML_VALUE)){
                logSb.append("\nRequest-Body: ");
                logSb.append(getRequestBody(request));
            }
        }
        if (logger.isInfoEnabled()){
            logStrLocal.set(logSb.toString());
//            logger.info(logSb.toString());
        }

    }

    @AfterReturning(value = "webLog()", returning = "ret")
    public void doAfterReturning(Object ret) throws Throwable {
        StringBuilder logSb = new StringBuilder();
        LocalDateTime now = LocalDateTime.now();
        logSb.append("\n>>>>>>>>>>>>>");
        logSb.append(String.format("\n结束计时: %s  耗时: %sms",dateTimeFormatter.format(now), now.toEpochSecond(ZoneOffset.ofHours(8)) - startTime.get()));
        logSb.append("\nHttp-接口响应").append("\nResponse-Body: \n").append(JSONObject.toJSON(ret));
        logSb.append("\n>>>>>>>>>>>>>");
        if (logger.isInfoEnabled()){
            logger.info(logStrLocal.get() + logSb.toString());
        }
    }

    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        return joinPoint.proceed(joinPoint.getArgs());
    }

    /**
     * 获取请求body
     * @param request
     * @return java.lang.String
     * @throws
     * @author shenyu
     * @date 2020/2/17 17: 34
     */
    private String getRequestBody(ServletRequest request) {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

}
